use std::collections::HashSet;
use std::hash::Hasher;
use async_graphql::Result as GraphQLResult;
use base64::Engine;
use base64::engine::general_purpose;
use bincode::{decode_from_slice, encode_to_vec, Decode, Encode};
use chrono::{Utc};
use tracing::{debug};
use twox_hash::XxHash64;

pub trait Claims: Encode + Decode<()> {
    fn expires_at(&self) -> u32;
}

#[derive(Debug, Clone)]
pub struct UserInfo {
    pub user_id: u64,
    pub authorities: HashSet<String>,
}

#[derive(Debug, Clone, Encode, Decode)]
pub struct AccessClaims {
    pub u: u64, // 用户ID
    pub a: HashSet<String>, // 权限
    pub e: u32, // 过期时间
}
impl Claims for AccessClaims {
    fn expires_at(&self) -> u32 {
        self.e
    }
}
#[derive(Debug, Clone, Encode, Decode)]
pub struct RefreshClaims {
    pub u: u64, // 用户ID
    pub e: u32, // 过期时间
    pub j: u64, // jti
}

impl Claims for RefreshClaims {
    fn expires_at(&self) -> u32 {
        self.e
    }
}

pub struct JwtUtil;

impl JwtUtil {
    // 生成JWT令牌
    pub fn generate_token(claims: impl Claims) -> GraphQLResult<String> {

        // 序列化 → 字节流
        let encoded: Vec<u8> = encode_to_vec(claims, bincode::config::standard())?;

        // 2. 计算哈希值（校验和）
        let mut hasher = XxHash64::with_seed(0); // 种子可自定义
        hasher.write(encoded.as_ref());

        let checksum = hasher.finish();


        // 将校验和和数据组合成一个字节向量
        // 先放校验和(8字节)，再放序列化数据
        let mut combined_data = Vec::with_capacity(8 + encoded.len());
        combined_data.extend_from_slice(&checksum.to_le_bytes()); // 8字节校验和
        combined_data.extend_from_slice(&encoded); // 序列化数据

        // 使用 URL 安全的 Base64 编码（适合 token）
        let token_string = general_purpose::URL_SAFE_NO_PAD.encode(&combined_data);
        debug!("Token: {}", token_string);

        Ok(token_string)
    }


    // 验证JWT令牌
    pub fn validate_token<T>(token: &str) -> GraphQLResult<T>
    where
        T: Claims,
    {

        // 解码
        let decoded_combined = general_purpose::URL_SAFE_NO_PAD.decode(token)?;


        // 分离校验和和数据
        if decoded_combined.len() < 8 {
            return Err("Invalid token format".into());
        }

        let (checksum_bytes, decoded_bytes) = decoded_combined.split_at(8);
        let received_checksum = u64::from_le_bytes(checksum_bytes.try_into()?);


        let mut new_hasher = XxHash64::with_seed(0);
        new_hasher.write(decoded_bytes.as_ref());
        let new_checksum = new_hasher.finish();

        if received_checksum.eq(&new_checksum) {
            debug!("校验和验证通过: {}", new_checksum);
        } else {
            return Err("Invalid token".into());
        }


        // 反序列化 → 结构体
        let (claims, _): (T, usize) = decode_from_slice(&decoded_bytes, bincode::config::standard())?;

        // 校验过期时间
        if claims.expires_at() < Utc::now().timestamp() as u32 {
            return Err("Token expired".into());
        }
        Ok(claims)
    }

    // // 刷新JWT令牌
    // pub fn refresh_token(refresh_token: &str, roles: HashSet<String>, authorities: HashSet<String>) -> GraphQLResult<(String, Option<(String, u64)>)> {
    //
    //
    //     let refresh_claims: RefreshClaims = Self::validate_token(refresh_token)?;
    //
    //     let token = Self::generate_token(AccessClaims {
    //         u: refresh_claims.u.clone(),
    //         r: roles,
    //         a: authorities,
    //         e: (Utc::now() + Duration::minutes(30)).timestamp() as u32,
    //     })?;
    //
    //     let jti = Snowflake::new(1,1).generate();
    //
    //     let two_days_later = (Utc::now() + Duration::days(2)).timestamp() as u32;
    //     let refresh_token = if refresh_claims.expires_at() < two_days_later {
    //         Some((Self::generate_token(RefreshClaims {
    //             u: refresh_claims.u.clone(),
    //             e: (Utc::now() + Duration::days(7)).timestamp() as u32,
    //             j: jti.clone(),
    //         })?, jti))
    //     } else {
    //          None
    //     };
    //
    //     Ok((token, refresh_token))
    // }
    //
    //
}